package com.feng.spring.hibernate.extend.processor;

import com.feng.spring.hibernate.extend.HibernateExtendFactory;
import com.feng.spring.hibernate.extend.conf.HibernateExtendConfiguration;
import com.feng.spring.hibernate.extend.core.DefaultHibernateExtendSQLBuilder;
import com.feng.spring.hibernate.extend.core.DefaultHibernateExtendSQLExecutor;
import com.feng.spring.hibernate.extend.core.HibernateExtendSQLRegistry;
import com.feng.spring.hibernate.extend.proxy.HibernateExtendFactoryBean;
import com.feng.spring.hibernate.extend.util.LocationUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.util.StringUtils;

import java.beans.Introspector;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.Set;

/**
 * hibernate拓展功能配置类
 */
public class HibernateExtendPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware, ResourceLoaderAware {

    private static final Logger logger = LoggerFactory.getLogger(HibernateExtendPostProcessor.class);
    private final String FACTORY_NAME = Introspector.decapitalize(HibernateExtendFactory.class.getSimpleName());
    static final String FACTORY_BEAN_OBJECT_TYPE = "factoryBeanObjectType";
    private ResourcePatternResolver resourcePatternResolver;
    private Environment environment;

    private HibernateExtendConfiguration configuration = new HibernateExtendConfiguration();

    private HibernateExtendSQLRegistry sqlRegistry = configuration.getRegistry();

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

        Set<Class<?>> classSet = new HashSet<>();
        String[] ls = LocationUtil.getLocations(environment).split(",|;");
        try {
            for (String location : ls) {
                if (StringUtils.hasText(location = location.trim())) {
                    Resource[] resources = getResourcePatternResolver().getResources(location);
                    for (Resource resource : resources) {
                        Class<?> clazz = this.sqlRegistry.cache(resource.getFilename(), resource.getContentAsString(StandardCharsets.UTF_8));
                        classSet.add(clazz);
                    }
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        // HibernateExtendFactory的注册建议放在bean中定义，因为没有引入springboot因此注册在这里
        BeanDefinitionBuilder builder1 = BeanDefinitionBuilder.genericBeanDefinition();
        AbstractBeanDefinition definition1 = builder1.getBeanDefinition();
        definition1.setBeanClass(HibernateExtendFactory.class);
        definition1.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
        definition1.getPropertyValues().add("hibernateExtendConfiguration", configuration);
        definition1.getPropertyValues().add("hibernateExtendSQLExecutor", new DefaultHibernateExtendSQLExecutor());
        definition1.getPropertyValues().add("hibernateExtendSQLBuilder", new DefaultHibernateExtendSQLBuilder());
        registry.registerBeanDefinition(FACTORY_NAME, definition1);

        for (Class<?> clazz : classSet) {
            if(!clazz.isInterface()){
                continue;
            }
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
            AbstractBeanDefinition definition = builder.getBeanDefinition();
            definition.setBeanClass(HibernateExtendFactoryBean.class);
            definition.getConstructorArgumentValues().addGenericArgumentValue(clazz);
            definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
            definition.setAttribute(FACTORY_BEAN_OBJECT_TYPE, clazz.getName());

            registry.registerBeanDefinition(Introspector.decapitalize(clazz.getSimpleName()), definition);
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
    }

    private ResourcePatternResolver getResourcePatternResolver() {
        if (this.resourcePatternResolver == null) {
            this.resourcePatternResolver = new PathMatchingResourcePatternResolver();
        }
        return this.resourcePatternResolver;
    }

}
